Processing Time Analysis¶
This notebook allows you to select and visualize processing time and read time data from marker location files.
Setup¶
Configure the base directory and define functions to find folders containing MarkerLocationsGA_CouchShift files.
In [28]:
import pandas as pd
import plotly.graph_objects as go
from plotly.subplots import make_subplots
import plotly.io as pio
import os
from pathlib import Path
# Configure Plotly for offline use in exports
pio.renderers.default = "notebook"
In [29]:
# Base directory for data
base_dir = r"C:\Users\kankean.kandasamy\Repo\KIM-QA-Analysis\Lyrebird Data"
# Column names for MarkerLocationsGA files (even if headers are missing)
GA_COLUMNS = [
'Frame No', 'Time (sec)', 'Gantry',
'Marker_0_AP', 'Marker_0_LR', 'Marker_0_SI',
'Marker_1_AP', 'Marker_1_LR', 'Marker_1_SI',
'Marker_2_AP', 'Marker_2_LR', 'Marker_2_SI',
'Marker_0_X', 'Marker_0_Y', 'Marker_1_X', 'Marker_1_Y', 'Marker_2_X', 'Marker_2_Y',
'Marker_0_Correlation', 'Marker_0_Segmentation',
'Marker_1_Correlation', 'Marker_1_Segmentation',
'Marker_2_Correlation', 'Marker_2_Segmentation',
'Joint Template', 'Processing Time (ms)', 'Read Time (ms)',
'HeaderTimeTag', 'Filename'
]
# Find all subdirectories
def find_folders(base_path):
folders = []
for root, dirs, filenames in os.walk(base_path):
# Check if this directory contains MarkerLocationsGA_CouchShift files
has_ga_files = any('MarkerLocationsGA_CouchShift' in f and f.endswith('.txt') for f in filenames)
if has_ga_files:
relative_path = os.path.relpath(root, base_path)
folders.append((relative_path, root))
return sorted(folders)
# Find all MarkerLocationsGA_CouchShift files in a folder
def find_ga_files_in_folder(folder_path):
files = []
for filename in os.listdir(folder_path):
if 'MarkerLocationsGA_CouchShift' in filename and filename.endswith('.txt'):
full_path = os.path.join(folder_path, filename)
files.append((filename, full_path))
return sorted(files)
available_folders = find_folders(base_dir)
print(f"Found {len(available_folders)} folders with MarkerLocationsGA_CouchShift files")
Found 17 folders with MarkerLocationsGA_CouchShift files
Plotting Functions¶
Define the data reading and plotting logic.
In [22]:
def plot_file(file_path, x_axis_col='Time (sec)', title=None):
"""Read a single data file and create interactive plots"""
try:
# Try reading with headers first
try:
df = pd.read_csv(file_path, skipinitialspace=True)
df.columns = df.columns.str.strip()
# Check if we have the expected columns
if 'Processing Time (ms)' not in df.columns:
raise ValueError("Missing expected columns")
except:
# Read without headers and assign column names
df = pd.read_csv(file_path, header=None, names=GA_COLUMNS, skipinitialspace=True)
# Extract relevant columns
x_data = df[x_axis_col]
processing_time = df['Processing Time (ms)']
read_time = df['Read Time (ms)']
# Create subplots with 2 rows
fig = make_subplots(
rows=2, cols=1,
subplot_titles=('Processing Time', 'Read Time'),
vertical_spacing=0.12,
shared_xaxes=True
)
# Add Processing Time trace (top panel)
fig.add_trace(
go.Scatter(
x=x_data,
y=processing_time,
mode='lines+markers',
name='Processing Time',
line=dict(color='#1f77b4', width=2),
marker=dict(size=4),
hovertemplate=f'{x_axis_col}: %{{x}}<br>Processing Time: %{{y:.2f}} ms<extra></extra>'
),
row=1, col=1
)
# Add Read Time trace (bottom panel)
fig.add_trace(
go.Scatter(
x=x_data,
y=read_time,
mode='lines+markers',
name='Read Time',
line=dict(color='#ff7f0e', width=2),
marker=dict(size=4),
hovertemplate=f'{x_axis_col}: %{{x}}<br>Read Time: %{{y:.2f}} ms<extra></extra>'
),
row=2, col=1
)
# Update axes labels
fig.update_xaxes(title_text=x_axis_col, row=2, col=1)
fig.update_yaxes(title_text='Processing Time (ms)', row=1, col=1)
fig.update_yaxes(title_text='Read Time (ms)', row=2, col=1)
# Use custom title if provided, otherwise generate from path
if title is None:
filename = os.path.basename(file_path)
folder_name = os.path.basename(os.path.dirname(file_path))
title = f'{folder_name} - {filename}'
fig.update_layout(
height=800,
showlegend=True,
hovermode='x unified',
title=dict(
text=f'<b>{title}</b>',
x=0.5,
xanchor='center'
),
font=dict(size=12)
)
# Enable pan and zoom
fig.update_xaxes(rangeslider_visible=False)
return fig, df
except Exception as e:
print(f"Error reading file {os.path.basename(file_path)}: {e}")
return None, None
def plot_folder(folder_path, x_axis='Time (sec)'):
"""
Plot all MarkerLocationsGA_CouchShift files in a folder and its subfolders (recursive).
Parameters:
-----------
folder_path : str
Relative path to folder (e.g., "2025-10-28" or "2025-10-28/Case4 - iso2 repeat")
or absolute path
x_axis : str
'Time (sec)' or 'Frame No'
"""
# Handle both relative and absolute paths
if not os.path.isabs(folder_path):
full_path = os.path.join(base_dir, folder_path)
else:
full_path = folder_path
if not os.path.exists(full_path):
print(f"Error: Folder not found: {full_path}")
return
# Recursively find all GA files in folder and subfolders
ga_files = []
for root, dirs, files in os.walk(full_path):
for filename in files:
if 'MarkerLocationsGA_CouchShift' in filename and filename.endswith('.txt'):
file_full_path = os.path.join(root, filename)
# Get the relative path from the selected folder
rel_path = os.path.relpath(root, full_path)
ga_files.append((rel_path, filename, file_full_path))
ga_files.sort() # Sort by relative path and filename
if not ga_files:
print(f"No MarkerLocationsGA_CouchShift files found in: {folder_path}")
return
selected_folder_name = os.path.basename(full_path)
print(f"Processing {len(ga_files)} file(s) from: {selected_folder_name} (including subfolders)\n")
for rel_path, filename, file_path in ga_files:
# Construct title: Selected Folder - Subfolder - Filename
if rel_path == '.':
# File is directly in the selected folder
title = f"{selected_folder_name} - {filename}"
print(f"Loading: {filename}")
else:
# File is in a subfolder
title = f"{selected_folder_name} - {rel_path} - {filename}"
print(f"Loading: {rel_path}\\{filename}")
fig, df = plot_file(file_path, x_axis, title=title)
if fig is not None:
fig.show()
print(f"\nData Summary for {filename}:")
print(f"Total Frames: {len(df)}")
print(f"\nProcessing Time (ms):")
print(f" Mean: {df['Processing Time (ms)'].mean():.2f}")
print(f" Median: {df['Processing Time (ms)'].median():.2f}")
print(f" Min: {df['Processing Time (ms)'].min():.2f}")
print(f" Max: {df['Processing Time (ms)'].max():.2f}")
print(f"\nRead Time (ms):")
print(f" Mean: {df['Read Time (ms)'].mean():.2f}")
print(f" Median: {df['Read Time (ms)'].median():.2f}")
print(f" Min: {df['Read Time (ms)'].min():.2f}")
print(f" Max: {df['Read Time (ms)'].max():.2f}")
print("\n" + "="*80 + "\n")
def list_folders():
"""List all available folders containing MarkerLocationsGA_CouchShift files"""
print(f"Available folders ({len(available_folders)}):\n")
for i, (name, path) in enumerate(available_folders, 1):
print(f"{i:2d}. {name}")
print("\nUsage: plot_folder('folder_path', x_axis='Time (sec)')")
Usage¶
Available Functions¶
list_folders()- List all available folders with data filesplot_folder(folder_path, x_axis='Time (sec)')- Plot all files in a folder and its subfolders (recursive)folder_path: Relative path from base directory (e.g.,"2025-10-28"or"2025-10-28/Case4 - iso2 repeat")x_axis: Either'Time (sec)'or'Frame No'- Searches recursively through all subfolders
plot_file(file_path, x_axis_col='Time (sec)', title=None)- Plot a single filetitle: Optional custom plot title
Step 1: List Available Folders¶
In [23]:
list_folders()
Available folders (17):
1. 2025-03-05 CTRO Static Tests Repeat
2. 2025-03-09 CTRO Static Tests with ImageX Phantom\Expt_9_03_2035\Couch_shift_5_5_6
3. 2025-03-09 CTRO Static Tests with ImageX Phantom\Expt_9_03_2035\Iso_volumeview_motionview
4. 2025-03-09 CTRO Static Tests with ImageX Phantom\Expt_9_03_2035\Marker_migrstion
5. 2025-03-18 CTRO Robot Repeat - Static Erratic and Persistent\Erratic
6. 2025-10-28\Case1 - iso1
7. 2025-10-28\Case2 - shift left 5 mm
8. 2025-10-28\Case3 - 5mm offset start, interruprt and shift according to KIM
9. 2025-10-28\Case4 - iso2 repeat
10. 2025-11-17
11. 2025-11-17\Lat shift present
12. 2025-11-20
13. 2025-11-26
14. 2025-12-02
15. 2025-12-02\Nice
16. Static Test
17. Trt_int_prersistant_excursion
Usage: plot_folder('folder_path', x_axis='Time (sec)')
Step 2: Plot Data from a Folder¶
Uncomment and modify the example below to plot your data:
In [30]:
# Example: Plot all files in folder and subfolders with Time on x-axis (default)
plot_folder("2025-10-28")
# Example: Plot with Frame No on x-axis
# plot_folder("2025-10-28", x_axis='Frame No')
# Example: Plot specific subfolder
# plot_folder("2025-10-28\\Case4 - iso2 repeat")
Processing 5 file(s) from: 2025-10-28 (including subfolders) Loading: Case1 - iso1\MarkerLocationsGA_CouchShift_0.txt
Data Summary for MarkerLocationsGA_CouchShift_0.txt: Total Frames: 1006 Processing Time (ms): Mean: 190.57 Median: 181.00 Min: 0.00 Max: 6081.00 Read Time (ms): Mean: 88.57 Median: 63.00 Min: 42.00 Max: 492.00 ================================================================================ Loading: Case2 - shift left 5 mm\MarkerLocationsGA_CouchShift_0.txt
Data Summary for MarkerLocationsGA_CouchShift_0.txt: Total Frames: 544 Processing Time (ms): Mean: 217.44 Median: 200.50 Min: 0.00 Max: 6625.00 Read Time (ms): Mean: 98.35 Median: 67.00 Min: 43.00 Max: 530.00 ================================================================================ Loading: Case3 - 5mm offset start, interruprt and shift according to KIM\MarkerLocationsGA_CouchShift_0.txt
Data Summary for MarkerLocationsGA_CouchShift_0.txt: Total Frames: 237 Processing Time (ms): Mean: 199.82 Median: 191.00 Min: 0.00 Max: 6221.00 Read Time (ms): Mean: 92.47 Median: 69.00 Min: 42.00 Max: 524.00 ================================================================================ Loading: Case3 - 5mm offset start, interruprt and shift according to KIM\MarkerLocationsGA_CouchShift_1.txt
Data Summary for MarkerLocationsGA_CouchShift_1.txt: Total Frames: 332 Processing Time (ms): Mean: 197.19 Median: 184.00 Min: 124.00 Max: 616.00 Read Time (ms): Mean: 79.17 Median: 58.00 Min: 45.00 Max: 404.00 ================================================================================ Loading: Case4 - iso2 repeat\MarkerLocationsGA_CouchShift_0.txt
Data Summary for MarkerLocationsGA_CouchShift_0.txt: Total Frames: 561 Processing Time (ms): Mean: 205.09 Median: 193.00 Min: 0.00 Max: 6462.00 Read Time (ms): Mean: 92.74 Median: 63.00 Min: 42.00 Max: 878.00 ================================================================================